package com.fjec.common.spring;


import com.fjec.common.enums.EnumSysCode;
import com.fjec.common.exception.PermissionException;
import com.fjec.common.protocol.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.management.ServiceNotFoundException;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.List;
import java.util.Set;

/**
 * 全局异常处理
 */
//@EnableWebMvc
//@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public JsonResult handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        String msg = EnumSysCode.ERR_0030.getMsg();
//        log.error(msg, e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0030.getCode())
                .message(msg)
                .build();
    }

    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public JsonResult handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        String msg = e.getMessage();
//        log.error(EnumSysCode.ERR_0031.getMsg(), e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0031.getCode())
                .message(msg)
                .build();
    }

    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public JsonResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        String msg = handleBindingResult(e.getBindingResult());
//        log.error(EnumSysCode.ERR_0032.getMsg(), e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0032.getCode())
                .message(msg)
                .build();
    }

    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public JsonResult handleBindException(BindException e) {
        String msg = handleBindingResult(e.getBindingResult());
//        log.error(EnumSysCode.ERR_0033.getMsg(), e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0033.getCode())
                .message(msg)
                .build();
    }

    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public JsonResult handleServiceException(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        String msg = violations.iterator().next().getMessage();
//        log.error(EnumSysCode.ERR_0034.getMsg(), e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0034.getCode())
                .message(msg)
                .build();
    }

    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ValidationException.class)
    public JsonResult handleValidationException(ValidationException e) {
        String msg = e.getMessage();
//        log.error(EnumSysCode.ERR_0034.getMsg(), e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0034.getCode())
                .message(msg)
                .build();
    }

    /**
     * 401 - Unauthorized
     */
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(PermissionException.class)
    public JsonResult handleLoginException(PermissionException e) {
        String msg = e.getMessage();
//        log.error(msg, e);
        return JsonResult.failure()
                .code(e.getCode())
                .message(msg)
                .build();
    }

    /**
     * 403 - Unauthorized
     */
    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ExceptionHandler(UnauthorizedException.class)
    public JsonResult handleLoginException(UnauthorizedException e) {
        String msg = e.getMessage();
//        log.error(EnumSysCode.ERR_0005.getMsg(), e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0005.getCode())
                .message(msg)
                .build();
    }

    /**
     * 405 - Method Not Allowed
     */
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public JsonResult handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        String msg = EnumSysCode.ERR_0035.getMsg();
//        log.error(msg, e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0035.getCode())
                .message(msg)
                .build();
    }

    /**
     * 415 - Unsupported Media Type
     */
    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public JsonResult handleHttpMediaTypeNotSupportedException(Exception e) {
        String msg = EnumSysCode.ERR_0036.getMsg();
//        log.error(msg, e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0036.getCode())
                .message(msg)
                .build();
    }

    /**
     * 422 - UNPROCESSABLE_ENTITY
     */
    @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public JsonResult handleMaxUploadSizeExceededException(Exception e) {
        String msg = EnumSysCode.ERR_0037.getMsg();
//        log.error(msg, e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0037.getCode())
                .message(msg)
                .build();
    }

    /**
     * 500 - Internal Server Error
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(ServiceNotFoundException.class)
    public JsonResult handleServiceException(ServiceNotFoundException e) {
        String msg = EnumSysCode.ERR_0038.getMsg() + e.getMessage();
//        log.error(msg, e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0038.getCode())
                .message(msg)
                .build();
    }

    /**
     * 500 - Internal Server Error
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public JsonResult handleException(Exception e) {
        String msg = EnumSysCode.ERR_0038.getMsg() + e.getMessage();
//        log.error(msg, e);
        return JsonResult.failure()
                .code(EnumSysCode.ERR_0038.getCode())
                .message(msg)
                .build();
    }

    /**
     * 处理参数绑定异常，并拼接出错的参数异常信息。
     *
     * @param result
     */
    private String handleBindingResult(BindingResult result) {
        if (result.hasErrors()) {
            final List<FieldError> fieldErrors = result.getFieldErrors();
            return fieldErrors.iterator().next().getDefaultMessage();
        }
        return null;
    }
}
